# @Time : 2020/6/28 10:56
# @Author : Fioman 
# @Phone : 13149920693
"""
闭包的一大特点是,延伸了函数的作用域.其中包含函数定义体中的引用,但是不在定义体中定义的非全局变量.
函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量.
"""


class Averager(object):
    def __init__(self):
        self.series = []

    def __call__(self, new_value):
        self.series.append(new_value)
        total = sum(self.series)
        return total / len(self.series)


avg = Averager()
print('1 = {}'.format(avg(10)))
print("2 = {}".format(avg(11)))
print("3 = {}".format(avg(12)))
print("4 = {}".format(avg(13)))


# 还可以使用另外一种方式,使用函数来实现
def make_averager():
    series = []  # 自由变量,相对于averager函数来说,因为它未在averager函数中定义绑定.

    def averager(new_value):
        series.append(new_value)
        total = sum(series)
        return total / len(series)

    return averager


avg = make_averager()
print('1 = {}'.format(avg(10)))
print("2 = {}".format(avg(11)))
print("3 = {}".format(avg(12)))
print("4 = {}".format(avg(13)))

print("avg var = {}".format(avg.__code__.co_varnames))
print("avg 自由变量 = {}".format(avg.__code__.co_freevars))
"""
综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定作用域不可用了,但是仍能使用那些绑定.
注意,只有嵌套在其他函数中的函数才可能需要处理不在全局作用域中的外部变量.
"""


# nonlocal声明

def make_averager_2():
    count = 0
    total = 0

    def averager(new_value):
        nonlocal count, total
        count += 1  # 这里不能直接使用,要声明为nonlocal类型,外部嵌套函数作用域
        total += new_value
        return total / count

    return averager
